﻿Imports System
Imports System.Globalization
Imports System.Security.Cryptography
Imports System.Text

Public Class ComputeAuthResponse
    ' Methods
    Public Sub SetCnonce(ByVal a As String)
        Me._cnonce = a
    End Sub
    Public Sub New(ByVal sid As String, ByVal password As String, ByVal domain As String, ByVal nonce As String, ByVal usingSHA1 As Boolean)
        Me._sid = sid
        Me._password = password
        Me._domain = domain
        Me._nonce = nonce
        Me._usingSHA1 = usingSHA1
        Dim seed As Integer = (DateTime.Now.DayOfYear * &HF4240)
        seed = (seed + (DateTime.Now.Hour * &H2710))
        seed = (seed + (DateTime.Now.Minute * 100))
        seed = (seed + DateTime.Now.Second)
        ComputeAuthResponse._random = New Random(seed)
    End Sub

    Public Shared Function BinaryToHex(ByVal [binary] As Byte()) As String
        Dim builder As New StringBuilder
        Dim num As Byte
        For Each num In [binary]
            If (num > 15) Then
                builder.AppendFormat("{0:X}", num)
            Else
                builder.AppendFormat("0{0:X}", num)
            End If
        Next
        Return builder.ToString
    End Function

    Private Function ComputeH1(ByVal key As Byte()) As String
        Dim s As String = String.Format(":{0}:{1}", Me._nonce, Me._cnonce)
        Dim bytes As Byte() = Encoding.UTF8.GetBytes(s)
        Dim array As Byte() = New Byte((key.Length + bytes.Length) - 1) {}
        key.CopyTo(array, 0)
        array.Copy(bytes, 0, array, key.Length, bytes.Length)
        Return ComputeAuthResponse.MD5ToHex(array)
    End Function

    Private Function ComputeH2() As String
        Dim s As String = String.Format("REGISTER:{0}", Me._sid)
        Return ComputeAuthResponse.MD5ToHex(Encoding.UTF8.GetBytes(s))
    End Function

    Private Function ComputeKey() As Byte()
        If Me._usingSHA1 Then
            Dim bytes As Byte() = Encoding.UTF8.GetBytes((Me._sid & ":" & Me._domain & ":"))
            Dim src As Byte() = ComputeAuthResponse.HexToBinary(Me._password.Substring(8))
            Dim dst As Byte() = New Byte((bytes.Length + src.Length) - 1) {}
            Buffer.BlockCopy(bytes, 0, dst, 0, bytes.Length)
            Buffer.BlockCopy(src, 0, dst, bytes.Length, src.Length)
            Return GetSha1(dst)
        End If
        Dim s As String = String.Format("{0}:{1}:{2}", Me._sid, Me._domain, Me._password)
        Return ComputeAuthResponse.GetMD5(Encoding.UTF8.GetBytes(s))
    End Function

    Public Function ComputeResponse() As String
        Dim key As Byte() = Me.ComputeKey
        Dim str As String = Me.ComputeH1(key)
        Dim str2 As String = Me.ComputeH2
        Return Me.ComputeResponse(str, str2)
    End Function

    Private Function ComputeResponse(ByVal h1 As String, ByVal h2 As String) As String
        Dim s As String = String.Format("{0}:{1}:{2}", h1, Me._nonce, h2)
        Return ComputeAuthResponse.MD5ToHex(Encoding.UTF8.GetBytes(s))
    End Function

    Private Shared Function GenNonce() As String
        Dim num As Integer = 0
        Dim num2 As Integer = 0
        Dim num3 As Integer = 0
        Dim num4 As Integer = 0
        SyncLock ComputeAuthResponse._random
            num = ComputeAuthResponse._random.Next
            num2 = ComputeAuthResponse._random.Next
            num3 = ComputeAuthResponse._random.Next
            num4 = ComputeAuthResponse._random.Next
        End SyncLock
        If ((num >> &H18) < &H10) Then
            num = (num + &H10000000)
        End If
        If ((num2 >> &H18) < &H10) Then
            num2 = (num2 + &H10000000)
        End If
        If ((num3 >> &H18) < &H10) Then
            num3 = (num3 + &H10000000)
        End If
        If ((num4 >> &H18) < &H10) Then
            num4 = (num4 + &H10000000)
        End If
        Return String.Format("{0:X}{1:X}{2:X}{3:X}", New Object() {num, num2, num3, num4})
    End Function

    Public Function GetCNonce() As String
        Me._cnonce = ComputeAuthResponse.GenNonce
        Return Me._cnonce
    End Function

    Public Shared Function HexToBinary(ByVal hex As String) As Byte()
        If ((hex Is Nothing) OrElse (hex.Length < 1)) Then
            Return New Byte(0 - 1) {}
        End If
        Dim num As Integer = (hex.Length / 2)
        Dim buffer As Byte() = New Byte(num - 1) {}
        num = (num * 2)
        Dim i As Integer
        For i = 0 To num - 1
            Dim num3 As Integer = Integer.Parse(hex.Substring(i, 2), NumberStyles.HexNumber)
            buffer((i / 2)) = CByte(num3)
            i += 1
        Next i
        Return buffer
    End Function

    Private Shared Function GetMD5(ByVal data As Byte()) As Byte()
        Using md5 As MD5 = MD5.Create
            Return MD5.ComputeHash(data)
        End Using
    End Function

    Private Shared Function MD5ToHex(ByVal data As Byte()) As String
        data = ComputeAuthResponse.GetMD5(data)
        Return ComputeAuthResponse.BinaryToHex(data)
    End Function
    Public Shared Function GetSha1(ByVal a As Byte()) As Byte()
        Using sha As SHA1 = SHA1.Create
            Return sha.ComputeHash(a)
        End Using
    End Function

    Public Shared Function GetSha1WithSalt(ByVal a As String, ByVal b As String) As String
        Using sha As SHA1 = SHA1.Create
            Dim pass As String = String.Concat(a, b)
            Dim passSha1 As Byte() = sha.ComputeHash(Encoding.UTF8.GetBytes(pass))
            Return BinaryToHex(passSha1).ToUpper
        End Using
    End Function

    ' Fields
    Private _cnonce As String
    Private _domain As String
    Private _nonce As String
    Private _password As String
    Private Shared _random As Random
    Private _sid As String
    Private _usingSHA1 As Boolean
End Class